package top.abilities.util.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;

import org.apache.shiro.SecurityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import top.abilities.util.enums.BucketEnum;
import top.abilities.util.param.AliOssParamVO;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.Buffer;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * Redis 工具类
 */
//@Component
public class OssClientUtil {

	@Autowired
	private AliOssParamVO aliOssParamVO;

	@Autowired
	private  OSSClient ossClient;

	private static AliOssParamVO staticAliOssParamVO;
	private  static OSSClient staticOssClient;

	private static Logger logger = LoggerFactory.getLogger(OssClientUtil.class);

	@PostConstruct
	public void init(){
		staticAliOssParamVO=aliOssParamVO;
		staticOssClient=ossClient;
	}

	/**

	 * 创建存储空间

	 * @param bucketName 存储空间

	 * @return

	 */
	public  static String createBucketName(String bucketName) throws Exception {
		//存储空间
		staticOssClient.setBucketAcl(bucketName,CannedAccessControlList.PublicRead);
		try{
			if(!staticOssClient.doesBucketExist(bucketName)){
				//创建存储空间
				Bucket bucket=staticOssClient.createBucket(bucketName);
				logger.info("创建存储空间成功");
				return bucket.getName();
			}
		}catch (Exception e){
			logger.error("bucketName 创建失败!");
			throw new Exception("bucketName 创建失败!");
		}
		return bucketName;
	}


	/**
	 * 删除存储空间buckName
	 * @param bucketName  存储空间
	 */
	public static  void deleteBucket(String bucketName) throws Exception{
		try {
			staticOssClient.deleteBucket(bucketName);
			logger.info("删除  " + bucketName + "  Bucket成功");
		}catch (Exception e){
			logger.error("删除{}Bucket成功,error:{}",bucketName,e.getMessage());
			throw new Exception(e.getMessage());
		}
	}



	/**
	 * 创建模拟文件夹
	 * @param bucketName 存储空间
	 * @param folder   文件夹名如
	 * @return  文件夹路径
	 */

	public  static String createFolder(String bucketName,String folder) throws Exception{
		//文件夹名
		final String keySuffixWithSlash =folder;
		try {
			//判断文件夹是否存在，不存在则创建
			if(!staticOssClient.doesObjectExist(bucketName, keySuffixWithSlash)){
				//创建文件夹
				staticOssClient.putObject(bucketName, keySuffixWithSlash, new ByteArrayInputStream(new byte[0]));
				logger.info("oss创建文件夹成功");
				//得到文件夹名
				OSSObject object = staticOssClient.getObject(bucketName, keySuffixWithSlash);
				String fileDir=object.getKey();
				return fileDir;
			}
		}catch (Exception e){
			logger.error("oss创建文件夹{}失败,error:{}",folder,e.getMessage());
			throw new Exception(e.getMessage());
		}
		return keySuffixWithSlash;

	}

	/**
	 * 根据key删除OSS服务器上的文件
	 * @param bucketName  存储空间
	 * @param folder  模拟文件夹名 如"qj_nanjing/"
	 * @param key Bucket下的文件的路径名+文件名 如："upload/cake.jpg"
	 */
	public static void deleteFile(String bucketName, String folder, String key){
		staticOssClient.deleteObject(bucketName, folder + key);
		logger.info("删除" + bucketName + "下的文件" + folder + key + "成功");

	}

    /**
     * 根据key删除OSS服务器上的文件
     * @param bucketName  存储空间
     * @param folder  模拟文件夹名 如"qj_nanjing/"
     */
    public static void deleteFiles(String bucketName, String folder) throws Exception {
        if (StringUtils.isEmpty(folder)){
            logger.info("删除" + bucketName + "的文件失败，路径为：" + folder);
            return;
        }
        ObjectListing objectListing = staticOssClient.listObjects(bucketName,folder);
        if (objectListing == null){
            logger.info("删除" + bucketName + "的文件失败，路径为：" + folder);
            return;
        }
        List<OSSObjectSummary> objectSummaries = objectListing.getObjectSummaries();
        for (OSSObjectSummary ss : objectSummaries) {
            staticOssClient.deleteObject(bucketName, ss.getKey());
        }
        createFolder(bucketName,folder);
        logger.info("删除" + bucketName + "下的文件" + folder  + "成功");
    }



	/**
	 * 上传图片至OSS  File 方式
	 * @param file 上传文件（文件全路径如：D:\\image\\cake.jpg）
	 * @param bucketName  存储空间
	 * @param folder 模拟文件夹名 如"feel/"
	 * @return String 返回的唯一MD5数字签名
	 * */
	public static  String uploadObject2OSS(File file, String bucketName, String folder) {
		String resultStr = null;
		try {
			//以输入流的形式上传文件
			InputStream inputStream = new FileInputStream(file);
			//文件名
			String fileName = file.getName();
			//文件大小
			Long fileSize = file.length();
			//上传文件   (上传文件流的形式)
			PutObjectResult putResult = staticOssClient.putObject(bucketName, folder + fileName, inputStream, getMetadata(fileName,fileSize));
			//解析结果
			resultStr = putResult.getETag();

		} catch (Exception e) {
			e.printStackTrace();
			logger.error("上传阿里云OSS服务器异常." + e.getMessage(), e);
		}
		return resultStr;

	}
	/**
	 * @Author chenxueliang
	 * @Date 2019/6/6 12:41
	 * @Desc 上传图片至OSS MultipartFile方式
	 **/
	public static  String uploadObject2OSSSByMF(MultipartFile file, String bucketName, String folder,String fileName) {
		String resultStr = null;
		try {
			//以输入流的形式上传文件
			InputStream is = file.getInputStream();
			//文件名
			//String fileName = file.getOriginalFilename();
			//文件大小
			Long fileSize = file.getSize();
			//上传文件   (上传文件流的形式)
			PutObjectResult putResult = staticOssClient.putObject(bucketName, folder + fileName, is, getMetadata(fileName,fileSize));
			//解析结果
			resultStr = putResult.getETag();

		} catch (Exception e) {
			e.printStackTrace();
			logger.error("上传阿里云OSS服务器异常." + e.getMessage(), e);
		}
		return resultStr;

	}



	/**
	 * @Author chenxueliang
	 * @Date 2019/6/6 12:41
	 * @Desc 上传图片至OSS MultipartFile方式
	 **/
	public static  String uploadObject2OSSSByMFLiu(	InputStream is , String bucketName, String folder,String fileName) {
		String resultStr = null;
		try {
			//以输入流的形式上传文件
			//文件名
			//String fileName = file.getOriginalFilename();
			//文件大小
			Long fileSize = Long.valueOf(is.available());
			//上传文件   (上传文件流的形式)
			PutObjectResult putResult = staticOssClient.putObject(bucketName, folder + fileName, is, getMetadata(fileName,fileSize));
			//解析结果
			resultStr = putResult.getETag();

		} catch (Exception e) {
			e.printStackTrace();
			logger.error("上传阿里云OSS服务器异常." + e.getMessage(), e);
		}
		return resultStr;

	}


	public static String uploadFileInStream(InputStream inputStream,String bucketName,String objectName){
		PutObjectResult putResult=staticOssClient.putObject(bucketName, objectName, inputStream);
		return putResult.getETag();
	}


	/**
	 * @Author chenxueliang
	 * @Date 2019/6/6 12:41
	 * @Desc 上传表情至OSS MultipartFile方式
	 **/
	public static  String uploadFaceOSSSByMF(MultipartFile file, String bucketName, String folder) {
		String resultStr = null;
		try {
			//以输入流的形式上传文件
			InputStream is = file.getInputStream();

			//文件名
			String fileName = file.getOriginalFilename();
			//文件大小
			Long fileSize = file.getSize();
			//上传文件   (上传文件流的形式)
			PutObjectResult putResult = staticOssClient.putObject(bucketName, folder + fileName, is, getMetadata(fileName,fileSize));

			//解析结果
			resultStr = putResult.getETag();

		} catch (Exception e) {
			e.printStackTrace();
			logger.error("上传阿里云OSS服务器异常." + e.getMessage(), e);
		}
		return resultStr;

	}


	/**

	 * 通过文件名判断并获取OSS服务文件上传时文件的contentType

	 * @param fileName 文件名

	 * @return 文件的contentType

	 */

	public static  String getContentType(String fileName){

		//文件的后缀名

		String fileExtension = fileName.substring(fileName.lastIndexOf("."));

		if(".bmp".equalsIgnoreCase(fileExtension)) {

			return "image/bmp";

		}
		if(".png".equalsIgnoreCase(fileExtension)) {

			return "image/png";

		}

		if(".gif".equalsIgnoreCase(fileExtension)) {

			return "image/gif";

		}

		if(".jpeg".equalsIgnoreCase(fileExtension) || ".jpg".equalsIgnoreCase(fileExtension)  || ".png".equalsIgnoreCase(fileExtension) ) {

			return "image/jpeg";

		}

		if(".html".equalsIgnoreCase(fileExtension)) {

			return "text/html";

		}

		if(".txt".equalsIgnoreCase(fileExtension)) {

			return "text/plain";

		}

		if(".vsd".equalsIgnoreCase(fileExtension)) {

			return "application/vnd.visio";

		}

		if(".ppt".equalsIgnoreCase(fileExtension) || "pptx".equalsIgnoreCase(fileExtension)) {

			return "application/vnd.ms-powerpoint";

		}

		if(".doc".equalsIgnoreCase(fileExtension) || "docx".equalsIgnoreCase(fileExtension)) {

			return "application/msword";

		}

		if(".xml".equalsIgnoreCase(fileExtension)) {

			return "text/xml";

		}
		if(".xlsx".equalsIgnoreCase(fileExtension)){
			return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
		}

		//默认返回类型

		return "image/jpeg";

	}

	private static ObjectMetadata getMetadata(String fileName,Long fileSize){
		//创建上传Object的Metadata
		ObjectMetadata metadata = new ObjectMetadata();
		//指定该Object被下载时的网页的缓存行为
		metadata.setCacheControl("no-cache");
		//上传的文件的长度
		metadata.setContentLength(fileSize);
		//指定该Object下设置Header
		metadata.setHeader("Pragma", "no-cache");
		//指定该Object被下载时的内容编码格式
		metadata.setContentEncoding("utf-8");
		//文件的MIME，定义文件的类型及网页编码，决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成，
		//如果没有扩展名则填默认值application/octet-stream
		metadata.setContentType(getContentType(fileName));
		//指定该Object被下载时的名称（指示MINME用户代理如何显示附加的文件，打开或下载，及文件名称）
		metadata.setContentDisposition("filename/filesize=" + fileName + "/" + fileSize + "Byte.");
		return metadata;
	}

	/**
	 * 获取权限url
	 * @param fileName
	 * @return
	 */
	public static String getAclUrl(String bucketName, String fileName){
		// 设置URL过期时间为1小时。
		Date expiration = new Date(new Date().getTime() + 3600 * 1000);
		// 生成URL FOLDER+File.separator+fileName
		URL url = staticOssClient.generatePresignedUrl(bucketName, staticAliOssParamVO.getKeyPicturesPrefix()+fileName, expiration);
		if (url != null) {
			return url.toString();
		}
		return "";
	}
	/**
	 * 获取权限url
	 * @param fileName
	 * @returnn
	 */
	public static String getUrl(String fileName, BucketEnum bucketEnum){
		StringBuffer buffer=new StringBuffer();
		buffer.append("http://");
		buffer.append(bucketEnum.getBucketACL().equals(2) ?  staticAliOssParamVO.getBucketFescoGap() : staticAliOssParamVO.getBucketFescoGapPriavte());
		buffer.append(".");
		buffer.append(staticAliOssParamVO.getEndpoint());
		buffer.append("/");
		buffer.append(staticAliOssParamVO.getKeyPicturesPrefix());
		buffer.append(fileName);
		return buffer.toString();
	}

	/**
	 * 获取权限url  表情
	 * @param fileName
	 * @returnn
	 */
	public static String getFaceUrl(String fileName,BucketEnum bucketEnum){
		StringBuffer buffer=new StringBuffer();
		buffer.append("http://");
		buffer.append(bucketEnum.getBucketACL().equals(2) ?  staticAliOssParamVO.getBucketFescoGap() : staticAliOssParamVO.getBucketFescoGapPriavte());
		buffer.append(".");
		buffer.append(staticAliOssParamVO.getEndpoint());
		buffer.append("/");
		buffer.append(staticAliOssParamVO.getKeyFacePrefix());
		buffer.append(fileName);
		return buffer.toString();
	}


	/**
	 * 获取权限url  导入错误文件路径   http://localhost:8087/manager/sys/export/downloadErrorExcel?bucketName=bucket-fesco-gap-priavte&filePath=fesco-dev/file/excel/李.jpg&cmpUserId=rewrewrwfsdfd/232
	 * filePath=bucketName+fillFullPath
	 * @param fileName
	 * @returnn
	 */
	public static String getExcelUrl(String fileName,BucketEnum bucketEnum){
//		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
		Object principal = SecurityUtils.getSubject().getPrincipal();
		JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(principal));
		Object cmpUserId = jsonObject.get("id");
		String cmpUserIdEncode = AESUtil.AESEncode(String.valueOf(cmpUserId));
//		StringBuffer requestURL = request.getRequestURL();
//		String requestURI = request.getRequestURI();
//		int index = requestURL.indexOf(requestURI);
//		String prefixUrl = requestURL.substring(0, index);
		StringBuffer buffer=new StringBuffer();
//		buffer.append(prefixUrl).append("/manager/sys/export/downloadErrorExcel?bucketName=");
		buffer.append("/manager/sys/export/downloadErrorExcel?bucketName=");
		buffer.append(bucketEnum.getBucketACL().equals(2) ?  staticAliOssParamVO.getBucketFescoGap() : staticAliOssParamVO.getBucketFescoGapPriavte());
		buffer.append("&").append("filePath=");
		buffer.append(staticAliOssParamVO.getKeyErrorExcelPrefix());
		buffer.append(fileName).append("&").append("cmpUserId=").append(cmpUserIdEncode);
		return buffer.toString();
	}


	/**
	 * 获取权限url  Banner
	 * @param fileName
	 * @returnn
	 */
	public static String getBannerUrl(String fileName, BucketEnum bucketEnum){
		StringBuffer buffer=new StringBuffer();
		buffer.append("https://");
		buffer.append(bucketEnum.getBucketACL().equals(2) ?  staticAliOssParamVO.getBucketFescoGap() : staticAliOssParamVO.getBucketFescoGapPriavte());
		buffer.append(".");
		buffer.append(staticAliOssParamVO.getEndpoint());
		buffer.append("/");
		buffer.append(staticAliOssParamVO.getKeyBannerPrefix());
		buffer.append(fileName);
		return buffer.toString();
	}

	/**
	 * 下载文件
	 * @param response
	 * @param bucketName
	 * @param ossKey 文件在oss上的全路径 比如：fesco-dev/file/excel/员工列表_1.xlsx，不含前缀/
	 * @throws IOException
	 */
	public static void download(HttpServletResponse response,String bucketName, String ossKey) throws IOException {
    	OSSObject object = staticOssClient.getObject(bucketName, ossKey);
		// 读去Object内容  返回
		BufferedInputStream in=new BufferedInputStream(object.getObjectContent());
		BufferedOutputStream out=new BufferedOutputStream(response.getOutputStream());
		//通知浏览器以附件形式下载
		String fileName = ossKey.substring(ossKey.lastIndexOf("/")+1);
		response.setHeader("Content-Disposition","attachment;filename="+ new String(fileName.replace(" ", "_").getBytes("UTF-8"), "ISO-8859-1"));
		try {
			byte[] car=new byte[2048];
			int temp=0;
			while((temp=in.read(car))!=-1){
				out.write(car, 0,temp);
			}
		} catch (IOException e) {
			logger.error("",e);
		} finally {
			if(out!=null){
				out.flush();
				out.close();
			}
			if(in!=null){
				in.close();
			}
		}
	}
}